/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.expression;

import de.odysseus.el.util.SimpleResolver;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.ValueExpression;
import javax.el.VariableMapper;

/**based on simple context
 *
 * @author eisental
 */

class dcContext extends ELContext {

    static class Functions extends FunctionMapper {
        Map<String, Method> map = new HashMap<String, Method>();

        public void setFunction(String prefix, String localName, Method method) {
            map.put(prefix + ":" + localName, method);
        }

        @Override
        public Method resolveFunction(String prefix, String localName) {
            return map.get(prefix + ":" + localName);
        }
    }

    static class Variables extends VariableMapper {
        Map<String, ValueExpression> map = new HashMap<String, ValueExpression>();
        dcContext context = null;

        @Override
        public ValueExpression resolveVariable(String variable) {
            //System.out.println("searching map for " + variable + ": ");

            if (map.containsKey(variable))
                return map.get(variable);

            if (!context.lookups.contains(variable)) context.lookups.add(variable);
            return null;
        }

        @Override
        public ValueExpression setVariable(String variable, ValueExpression expression) {
            return map.put(variable, expression);
        }


    }

    private Functions functions;
    private Variables variables;
    private ELResolver resolver;
    private List<String> lookups = new ArrayList<String>();

    /**
    * Create a context.
    */
    public dcContext() {

        this.resolver = new SimpleResolver();

    }

    public List<String> getNameLookups() {
        return lookups;
    }
    /**
     * Define a function
     */
    public void setFunction(String prefix, String localName, Method method) {
        if (functions == null) {
            functions = new Functions();
        }
        functions.setFunction(prefix, localName, method);
    }

    /**
     * Define a variable
     */
    public ValueExpression setVariable(String name, ValueExpression expression) {
        if (variables == null) {
            variables = new Variables();
            variables.context = this;
        }
        return variables.setVariable(name, expression);
    }

    /**
     * Get our function mapper.
     */
    @Override
    public FunctionMapper getFunctionMapper() {
        return functions;
    }

    /**
     * Get our variable mapper.
     */
    @Override
    public VariableMapper getVariableMapper() {
        return variables;
    }

    /**
     * Get our resolver.
     * Lazy initialize a {@link SimpleResolver}.
     */
    @Override
    public ELResolver getELResolver() {
        if (resolver == null) {
            resolver = new SimpleResolver();
        }
        return resolver;
    }
}